#include "desc.h"
#include "main.h"
#include <sum_usbfs.h>
#include <util_bit.h>
#include <util_trans.h>
#include <util_usb_desc_cdc.h>
#include <util_usb_std_req.h>

#define MAX_EP0_SIZE_2_POWER 6
#define MAX_EP0_SIZE (1 << MAX_EP0_SIZE_2_POWER)
#define MAX_EP0_WORD_NUMS_2_POWER (MAX_EP0_SIZE_2_POWER - 2)
#define MAX_EP0_WORD_NUMS (1 << MAX_EP0_WORD_NUMS_2_POWER)

u32_s g_ep0_recv_buf_a[MAX_EP0_WORD_NUMS] = {};
u8_s g_ep0_recv_buf_word_nums = 0;
u8_s g_dir = 0;

// 使能断点0（给定方向）
static void _ep0_en_dir(usbfs_ep_re dir) {
	usbfs_depctl_expl_s depctl = {
		.max_pkt_len = 0, // 端点0此字段为0表示64字节
		.active = 1,
		.even_odd_pid = 0,
		.nak_stat = 0,
		.ep_type = USB_TRANS_CTRL,
		.snoop_mode_en = 0,
		.stall_en = 0,
		.trans_fifo_no = 0,
		.clear_nak = 1,
		.set_nak = 0,
		.set_even_data0 = 0,
		.set_odd_data1 = 0,
		.ep_di = 0,
		.ep_en_start = 1,
	};
	usbfs_set_ep_ctl(dir, USBFS_EP0_RR, depctl);
}

// 端点0的IN使能
static void _ep0_in_enable(void) {
	trans_write_str("In enable.\n", put_byte_to_fifo);
	_ep0_en_dir(USBFS_EP_DI_R);
}

// 端点0的OUT使能
static void _ep0_out_enable(void) {
	trans_write_str("Out enable.\n", put_byte_to_fifo);
	_ep0_en_dir(USBFS_EP_DO_R);
}

// 端点0的IN STALL
static void _ep0_in_stall(void) {
	trans_write_str("In stall.\n", put_byte_to_fifo);
	usbfs_depctl_expl_s depctl = {
		.max_pkt_len = 0, // 端点0此字段为0表示64字节
		.active = 1,
		.even_odd_pid = 0,
		.nak_stat = 0,
		.ep_type = USB_TRANS_CTRL,
		.snoop_mode_en = 0,
		.stall_en = 1,
		.trans_fifo_no = 0,
		.clear_nak = 0,
		.set_nak = 0,
		.set_even_data0 = 0,
		.set_odd_data1 = 0,
		.ep_di = 0,
		.ep_en_start = 1,
	};
	usbfs_set_ep_ctl(USBFS_EP_DI_R, USBFS_EP0_RR, depctl);
}

// 端点0发送数据
static void _ep0_start_send(const u32_s space_b[], u32_s total_size,
			    u32_s req_size) {
	u32_s size = total_size;
	if (size > req_size) {
		size = req_size;
	}
	u32_s packet_nums = (size >> MAX_EP0_SIZE_2_POWER) + 1;
	usbfs_deplen_expl_s diep0len = {
		.total_size = size,
		.pkt_nums = packet_nums,
		.pid_nums = 0,
	};
	usbfs_set_trans_len(USBFS_EP_DI_R, USBFS_EP0_RR, diep0len);
	_ep0_in_enable();
	u32_s word_nums = bit_right_shift_upper(size, 2);
	for (u32_s i = 0; i < word_nums; i++) {
		usbfs_wreg_fifo(USBFS_FIFO0_R, space_b[i]);
	}
	trans_write_str("Send size = ", put_byte_to_fifo);
	trans_write_udec(size, put_byte_to_fifo);
	trans_write_str(", word_nums = ", put_byte_to_fifo);
	trans_write_udec(word_nums, put_byte_to_fifo);
	trans_write_str(".\n", put_byte_to_fifo);
}

// 设置设备地址并发送确认包
static void _set_dev_addr(u32_s addr) {
	usbfs_dcfg_expl_s dcfg = {
		.speed = USBFS_DS_FULL_SPEED,
		.non_zero_len_pkt_stall_en = 0,
		.dev_addr = addr,
		.periodic_frame_end_time = 0,
	};
	usbfs_set_dev_cfg_s(dcfg);
	_ep0_start_send(0, 0, 0);
}

// 发送设备描述符
static void _send_dev_desc(u32_s req_size) {
	u32_s size;
	usbfs_dcfg_expl_s dcfg = usbfs_get_dev_cfg_s();
	if (dcfg.dev_addr == 0) {
		size = 8;
	} else {
		size = sizeof(usb_desc_dev_t);
	}
	_ep0_start_send((const u32_s*)&g_cdc_acm_dev_desc, size, req_size);
}

// 发送配置描述符集合
static void _send_desc_set(u32_s req_size) {
	_ep0_start_send((const u32_s*)&g_cdc_acm_desc_set,
			sizeof(usb_desc_set_cdc_t), req_size);
}

// 响应获取描述符请求
static void _desc_req(__attribute__((aligned(4))) const usb_std_req_t* req_p) {
	switch (req_p->para >> 8) {
	case 1: // 设备描述符
		_send_dev_desc(req_p->len);
		break;
	case 2: // 配置描述符
		_send_desc_set(req_p->len);
		break;
	case 6: // 限定描述符
		_ep0_in_stall();
		break;
	}
}

// 端点0接收数据
static void _ep0_recv(u32_s pkt_nums, u32_s size) {
	trans_write_str("Read ", put_byte_to_fifo);
	trans_write_udec(pkt_nums, put_byte_to_fifo);
	trans_write_str(" packets ", put_byte_to_fifo);
	trans_write_udec(size, put_byte_to_fifo);
	trans_write_str(" bytes.\n", put_byte_to_fifo);
	usbfs_deplen_expl_s doep0len = {
		.total_size = size,
		.pkt_nums = pkt_nums,
		.pid_nums = 0,
	};
	usbfs_set_trans_len(USBFS_EP_DO_R, USBFS_EP0_RR, doep0len);
}

// 接收串口初始配置
static void _recv_init_cfg(u32_s size) {
	u32_s pkt_nums = bit_right_shift_upper(size, MAX_EP0_SIZE_2_POWER);
	u32_s recv_size = pkt_nums << MAX_EP0_SIZE_2_POWER;
	_ep0_recv(pkt_nums, recv_size);
	_ep0_out_enable();
}

// 处理端点0的STPF中断
static void _oep0_stpf(const u32_s buf_b[]) {
	const usb_std_req_t* req_p = (const usb_std_req_t*)buf_b;
	u32_s dir = req_p->dir;
	g_dir = dir;
	switch (req_p->cmd) {
	case 5:
		_set_dev_addr(req_p->para);
		break;
	case 6:
		_desc_req(req_p);
		break;
	case 9:
		_ep0_start_send(0, 0, 0);
		break;
	case 32:
		_recv_init_cfg(req_p->len);
		break;
	}
}

// 处理端点0的OEP中断
static void _oep0_irq(void) {
	usbfs_doepint_expl_s doep0intf =
		usbfs_get_dev_out_int_flags(USBFS_EP0_RR);
	usbfs_clear_dev_out_int_flags(USBFS_EP0_RR, doep0intf);
	if (doep0intf.setup_phase_finish) {
		trans_write_str("Setup finish irq.\n", put_byte_to_fifo);
		if (g_ep0_recv_buf_word_nums != 0) {
			_oep0_stpf(g_ep0_recv_buf_a);
			g_ep0_recv_buf_word_nums = 0;
		}
	} else if (doep0intf.trans_finish) {
		trans_write_str("Out finish irq.\n", put_byte_to_fifo);
		if (g_ep0_recv_buf_word_nums != 0) {
			// TODO
		}
	}
}

// 处理OEP中断
static void _oep_irq(void) {
	usbfs_daepint_expl_s flags = usbfs_get_dep_ep_int_flags();
	if (flags.in_ep0_int) {
		_oep0_irq();
	}
}

// 处理IEP的TF中断
static void _iep0_tf(void) {
	usbfs_deptfstat_expl_s diep0tfstat =
		usbfs_get_fifo_stat_s(USBFS_EP_DI_R, USBFS_EP0_RR);
	trans_write_str("In finish irq. DIEP0TFSTAT = 0x", put_byte_to_fifo);
	trans_write_uhex(diep0tfstat.fifo_remain_32b_nums, 8, put_byte_to_fifo);
	trans_write_str(".\n", put_byte_to_fifo);
	if (g_dir) {
		_ep0_recv(1, 0);
		_ep0_out_enable();
	}
}

// 处理端点0的IEP中断
static void _iep0_irq(void) {
	usbfs_diepint_expl_s diep0intf =
		usbfs_get_dev_in_int_flags(USBFS_EP0_RR);
	usbfs_clear_dev_in_int_flags(USBFS_EP0_RR, diep0intf);
	if (diep0intf.trans_finish) {
		_iep0_tf();
	}
	if (diep0intf.ctrl_in_timeout) {
		trans_write_str("CITO.\n", put_byte_to_fifo);
	}
}

// 处理IEP中断
static void _iep_irq(void) {
	usbfs_daepint_expl_s flags = usbfs_get_dep_ep_int_flags();
	if (flags.in_ep0_int) {
		_iep0_irq();
	}
}

// 处理端点0的RXFNE中断
static void _ep0_rxne_irq(usbfs_grstat_dev_expl_s grstat) {
	trans_write_str("EP0 RXNE irq. RPCKST = ", put_byte_to_fifo);
	trans_write_udec(grstat.stat, put_byte_to_fifo);
	trans_write_str(", size = ", put_byte_to_fifo);
	trans_write_udec(grstat.size, put_byte_to_fifo);
	trans_write_str(".\n", put_byte_to_fifo);
	usbfs_grstat_dev_rpckst_e stat = grstat.stat;
	if (stat == USBFS_GRSTAT_DEV_OUT || stat == USBFS_GRSTAT_DEV_SETUP) {
		u32_s size = grstat.size;
		u32_s word_nums = bit_right_shift_upper(size, 2);
		g_ep0_recv_buf_word_nums = word_nums;
		trans_write_str("Recv data, size = ", put_byte_to_fifo);
		trans_write_udec(size, put_byte_to_fifo);
		put_byte_to_fifo(':');
		for (u32_s i = 0; i < word_nums; i++) {
			u32_s data = usbfs_rreg_fifo(USBFS_FIFO0_R);
			g_ep0_recv_buf_a[i] = data;
			for (u32_s j = 0; j < sizeof(u32_s); j++) {
				trans_write_str(" 0x", put_byte_to_fifo);
				trans_write_uhex(data >> (j << 3), 2,
						 put_byte_to_fifo);
			}
		}
		trans_write_str(".\n", put_byte_to_fifo);
	}
}

// 处理RXFNE中断
static void _rxne_irq(void) {
	usbfs_grstat_dev_expl_s grstat = usbfs_pop_recv_stat();
	u32_s ep_no = grstat.ep_no;
	if (ep_no == 0) {
		_ep0_rxne_irq(grstat);
	}
}

// USB中断入口
void usbfs_irq(void) {
	usbfs_gint_expl_s gintf = usbfs_get_int_flags();
	usbfs_clear_int_flags(gintf);
	if (gintf.out_ep) {
		_oep_irq();
	}
	if (gintf.in_ep) {
		_iep_irq();
	}
	if (gintf.recv_fifo_non_empty) {
		_rxne_irq();
	}
	if (gintf.reset) {
		trans_write_str("Reset irq.\n", put_byte_to_fifo);
	}
	if (gintf.enum_finish) {
		trans_write_str("Enum irq.\n", put_byte_to_fifo);
	}
}
